use axum::extract::rejection::JsonRejection;
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use thiserror::Error;
use tracing::error;

pub type AppResult<T> = Result<AppResp<T>, AppError>;

// Make our own error that wraps `anyhow::Error`.
#[derive(Debug, Error)]
pub enum AppError {
    // 校验错误
    #[error(transparent)]
    ValidationError(#[from] validator::ValidationErrors),
    // 请求体json格式错误
    #[error(transparent)]
    AxumJsonRejection(#[from] JsonRejection),
    // 用户未提供身份验证凭据，或者没有通过身份验证。
    #[error("身份验证失败: {0}")]
    Unauthorized(String),
    // 其他错误
    #[error(transparent)]
    AnyError(#[from] anyhow::Error),
}

// Tell axum how to convert `AppError` into a response.
impl IntoResponse for AppError {
    fn into_response(self) -> Response {
        error!("error handling request: {:?}", self);
        match self {
            AppError::ValidationError(e) => {
                AppResp::<()>::param_error(e.to_string()).into_response()
            }
            AppError::AxumJsonRejection(e) => {
                (e.status(), AppResp::<()>::param_error(e.body_text())).into_response()
            }
            AppError::AnyError(_) => {
                AppResp::<()>::server_error().into_response()
            }
            AppError::Unauthorized(e) => {
                (StatusCode::UNAUTHORIZED, AppResp::<()>::param_error(e)).into_response()
            }
        }
    }
}

// #[derive(FromRequest)]
// #[from_request(via(axum::Json), rejection(AppError))]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AppResp<T> {
    pub code: AppStatusCode,
    pub message: String,
    pub data: Option<T>,
}

impl<T: Serialize> IntoResponse for AppResp<T> {
    fn into_response(self) -> Response {
        axum::Json(self).into_response()
    }
}

#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, Serialize_repr, Deserialize_repr)]
#[repr(u32)]
pub enum AppStatusCode {
    Success = 200,
    ParamError = 403,
    ServerError = 500,
}

impl AppStatusCode {
    fn get_message(&self) -> String {
        match self {
            AppStatusCode::Success => {
                "成功"
            }
            AppStatusCode::ParamError => {
                "参数错误"
            }
            AppStatusCode::ServerError => {
                "服务端异常"
            }
        }.to_string()
    }
}

impl<T> AppResp<T> {
    pub fn success(data: T) -> Self {
        AppResp {
            code: AppStatusCode::Success,
            message: AppStatusCode::Success.get_message(),
            data: Some(data),
        }
    }
    pub fn success_empty() -> AppResp<()> {
        AppResp {
            code: AppStatusCode::Success,
            message: AppStatusCode::Success.get_message(),
            data: None,
        }
    }
    pub fn server_error() -> AppResp<()> {
        AppResp {
            code: AppStatusCode::ServerError,
            message: AppStatusCode::ServerError.get_message(),
            data: None,
        }
    }
    pub fn param_error(msg: String) -> AppResp<()> {
        AppResp {
            code: AppStatusCode::ParamError,
            message: msg,
            data: None,
        }
    }
    pub fn error(app_code: AppStatusCode) -> AppResp<()> {
        AppResp {
            code: app_code,
            message: app_code.get_message(),
            data: None,
        }
    }
}

impl<T: Serialize> From<T> for AppResp<T> {
    fn from(value: T) -> Self {
        AppResp::success(value)
    }
}
